﻿/********************************************************************
	created:	2011-8-14   10:01
	author:		Lifan Su
	
	purpose:    implement of CRC-32 functions
*********************************************************************/

#include "crc32.h"
#include <cvt_int_mem.h>
#include "hex_to_char.h"

#include <assert.h>
#include <_inttypes.h>


static const uint32_t crc32_table[256] = {
    UINT32_C(0x00000000), UINT32_C(0x96300777), UINT32_C(0x2C610EEE), UINT32_C(0xBA510999),
    UINT32_C(0x19C46D07), UINT32_C(0x8FF46A70), UINT32_C(0x35A563E9), UINT32_C(0xA395649E),
    UINT32_C(0x3288DB0E), UINT32_C(0xA4B8DC79), UINT32_C(0x1EE9D5E0), UINT32_C(0x88D9D297),
    UINT32_C(0x2B4CB609), UINT32_C(0xBD7CB17E), UINT32_C(0x072DB8E7), UINT32_C(0x911DBF90),
    UINT32_C(0x6410B71D), UINT32_C(0xF220B06A), UINT32_C(0x4871B9F3), UINT32_C(0xDE41BE84),
    UINT32_C(0x7DD4DA1A), UINT32_C(0xEBE4DD6D), UINT32_C(0x51B5D4F4), UINT32_C(0xC785D383),
    UINT32_C(0x56986C13), UINT32_C(0xC0A86B64), UINT32_C(0x7AF962FD), UINT32_C(0xECC9658A),
    UINT32_C(0x4F5C0114), UINT32_C(0xD96C0663), UINT32_C(0x633D0FFA), UINT32_C(0xF50D088D),
    UINT32_C(0xC8206E3B), UINT32_C(0x5E10694C), UINT32_C(0xE44160D5), UINT32_C(0x727167A2),
    UINT32_C(0xD1E4033C), UINT32_C(0x47D4044B), UINT32_C(0xFD850DD2), UINT32_C(0x6BB50AA5),
    UINT32_C(0xFAA8B535), UINT32_C(0x6C98B242), UINT32_C(0xD6C9BBDB), UINT32_C(0x40F9BCAC),
    UINT32_C(0xE36CD832), UINT32_C(0x755CDF45), UINT32_C(0xCF0DD6DC), UINT32_C(0x593DD1AB),
    UINT32_C(0xAC30D926), UINT32_C(0x3A00DE51), UINT32_C(0x8051D7C8), UINT32_C(0x1661D0BF),
    UINT32_C(0xB5F4B421), UINT32_C(0x23C4B356), UINT32_C(0x9995BACF), UINT32_C(0x0FA5BDB8),
    UINT32_C(0x9EB80228), UINT32_C(0x0888055F), UINT32_C(0xB2D90CC6), UINT32_C(0x24E90BB1),
    UINT32_C(0x877C6F2F), UINT32_C(0x114C6858), UINT32_C(0xAB1D61C1), UINT32_C(0x3D2D66B6),

    UINT32_C(0x9041DC76), UINT32_C(0x0671DB01), UINT32_C(0xBC20D298), UINT32_C(0x2A10D5EF),
    UINT32_C(0x8985B171), UINT32_C(0x1FB5B606), UINT32_C(0xA5E4BF9F), UINT32_C(0x33D4B8E8),
    UINT32_C(0xA2C90778), UINT32_C(0x34F9000F), UINT32_C(0x8EA80996), UINT32_C(0x18980EE1),
    UINT32_C(0xBB0D6A7F), UINT32_C(0x2D3D6D08), UINT32_C(0x976C6491), UINT32_C(0x015C63E6),
    UINT32_C(0xF4516B6B), UINT32_C(0x62616C1C), UINT32_C(0xD8306585), UINT32_C(0x4E0062F2),
    UINT32_C(0xED95066C), UINT32_C(0x7BA5011B), UINT32_C(0xC1F40882), UINT32_C(0x57C40FF5),
    UINT32_C(0xC6D9B065), UINT32_C(0x50E9B712), UINT32_C(0xEAB8BE8B), UINT32_C(0x7C88B9FC),
    UINT32_C(0xDF1DDD62), UINT32_C(0x492DDA15), UINT32_C(0xF37CD38C), UINT32_C(0x654CD4FB),
    UINT32_C(0x5861B24D), UINT32_C(0xCE51B53A), UINT32_C(0x7400BCA3), UINT32_C(0xE230BBD4),
    UINT32_C(0x41A5DF4A), UINT32_C(0xD795D83D), UINT32_C(0x6DC4D1A4), UINT32_C(0xFBF4D6D3),
    UINT32_C(0x6AE96943), UINT32_C(0xFCD96E34), UINT32_C(0x468867AD), UINT32_C(0xD0B860DA),
    UINT32_C(0x732D0444), UINT32_C(0xE51D0333), UINT32_C(0x5F4C0AAA), UINT32_C(0xC97C0DDD),
    UINT32_C(0x3C710550), UINT32_C(0xAA410227), UINT32_C(0x10100BBE), UINT32_C(0x86200CC9),
    UINT32_C(0x25B56857), UINT32_C(0xB3856F20), UINT32_C(0x09D466B9), UINT32_C(0x9FE461CE),
    UINT32_C(0x0EF9DE5E), UINT32_C(0x98C9D929), UINT32_C(0x2298D0B0), UINT32_C(0xB4A8D7C7),
    UINT32_C(0x173DB359), UINT32_C(0x810DB42E), UINT32_C(0x3B5CBDB7), UINT32_C(0xAD6CBAC0),

    UINT32_C(0x2083B8ED), UINT32_C(0xB6B3BF9A), UINT32_C(0x0CE2B603), UINT32_C(0x9AD2B174),
    UINT32_C(0x3947D5EA), UINT32_C(0xAF77D29D), UINT32_C(0x1526DB04), UINT32_C(0x8316DC73),
    UINT32_C(0x120B63E3), UINT32_C(0x843B6494), UINT32_C(0x3E6A6D0D), UINT32_C(0xA85A6A7A),
    UINT32_C(0x0BCF0EE4), UINT32_C(0x9DFF0993), UINT32_C(0x27AE000A), UINT32_C(0xB19E077D),
    UINT32_C(0x44930FF0), UINT32_C(0xD2A30887), UINT32_C(0x68F2011E), UINT32_C(0xFEC20669),
    UINT32_C(0x5D5762F7), UINT32_C(0xCB676580), UINT32_C(0x71366C19), UINT32_C(0xE7066B6E),
    UINT32_C(0x761BD4FE), UINT32_C(0xE02BD389), UINT32_C(0x5A7ADA10), UINT32_C(0xCC4ADD67),
    UINT32_C(0x6FDFB9F9), UINT32_C(0xF9EFBE8E), UINT32_C(0x43BEB717), UINT32_C(0xD58EB060),
    UINT32_C(0xE8A3D6D6), UINT32_C(0x7E93D1A1), UINT32_C(0xC4C2D838), UINT32_C(0x52F2DF4F),
    UINT32_C(0xF167BBD1), UINT32_C(0x6757BCA6), UINT32_C(0xDD06B53F), UINT32_C(0x4B36B248),
    UINT32_C(0xDA2B0DD8), UINT32_C(0x4C1B0AAF), UINT32_C(0xF64A0336), UINT32_C(0x607A0441),
    UINT32_C(0xC3EF60DF), UINT32_C(0x55DF67A8), UINT32_C(0xEF8E6E31), UINT32_C(0x79BE6946),
    UINT32_C(0x8CB361CB), UINT32_C(0x1A8366BC), UINT32_C(0xA0D26F25), UINT32_C(0x36E26852),
    UINT32_C(0x95770CCC), UINT32_C(0x03470BBB), UINT32_C(0xB9160222), UINT32_C(0x2F260555),
    UINT32_C(0xBE3BBAC5), UINT32_C(0x280BBDB2), UINT32_C(0x925AB42B), UINT32_C(0x046AB35C),
    UINT32_C(0xA7FFD7C2), UINT32_C(0x31CFD0B5), UINT32_C(0x8B9ED92C), UINT32_C(0x1DAEDE5B),

    UINT32_C(0xB0C2649B), UINT32_C(0x26F263EC), UINT32_C(0x9CA36A75), UINT32_C(0x0A936D02),
    UINT32_C(0xA906099C), UINT32_C(0x3F360EEB), UINT32_C(0x85670772), UINT32_C(0x13570005),
    UINT32_C(0x824ABF95), UINT32_C(0x147AB8E2), UINT32_C(0xAE2BB17B), UINT32_C(0x381BB60C),
    UINT32_C(0x9B8ED292), UINT32_C(0x0DBED5E5), UINT32_C(0xB7EFDC7C), UINT32_C(0x21DFDB0B),
    UINT32_C(0xD4D2D386), UINT32_C(0x42E2D4F1), UINT32_C(0xF8B3DD68), UINT32_C(0x6E83DA1F),
    UINT32_C(0xCD16BE81), UINT32_C(0x5B26B9F6), UINT32_C(0xE177B06F), UINT32_C(0x7747B718),
    UINT32_C(0xE65A0888), UINT32_C(0x706A0FFF), UINT32_C(0xCA3B0666), UINT32_C(0x5C0B0111),
    UINT32_C(0xFF9E658F), UINT32_C(0x69AE62F8), UINT32_C(0xD3FF6B61), UINT32_C(0x45CF6C16),
    UINT32_C(0x78E20AA0), UINT32_C(0xEED20DD7), UINT32_C(0x5483044E), UINT32_C(0xC2B30339),
    UINT32_C(0x612667A7), UINT32_C(0xF71660D0), UINT32_C(0x4D476949), UINT32_C(0xDB776E3E),
    UINT32_C(0x4A6AD1AE), UINT32_C(0xDC5AD6D9), UINT32_C(0x660BDF40), UINT32_C(0xF03BD837),
    UINT32_C(0x53AEBCA9), UINT32_C(0xC59EBBDE), UINT32_C(0x7FCFB247), UINT32_C(0xE9FFB530),
    UINT32_C(0x1CF2BDBD), UINT32_C(0x8AC2BACA), UINT32_C(0x3093B353), UINT32_C(0xA6A3B424),
    UINT32_C(0x0536D0BA), UINT32_C(0x9306D7CD), UINT32_C(0x2957DE54), UINT32_C(0xBF67D923),
    UINT32_C(0x2E7A66B3), UINT32_C(0xB84A61C4), UINT32_C(0x021B685D), UINT32_C(0x942B6F2A),
    UINT32_C(0x37BE0BB4), UINT32_C(0xA18E0CC3), UINT32_C(0x1BDF055A), UINT32_C(0x8DEF022D)
};

CRYPT_HASH_PREFIX void CRYPT_HASH_API crc32_d_read(struct CRC32_d *dst, const void *src)
{
    assert(dst && src && "Non-null pointer");

   dst->hash[0] = cvt_byte_to_u32_be(src);
}

CRYPT_HASH_PREFIX void CRYPT_HASH_API crc32_d_write(void *dst, const struct CRC32_d *src)
{
    assert(dst && src && "Non-null pointer");

    cvt_u32_be_to_byte(dst, src->hash[0]);
}

CRYPT_HASH_PREFIX void CRYPT_HASH_API crc32_d_print(char *dst, const struct CRC32_d *src)
{
    int i, j;

    assert(dst && src && "Non-null pointer");

    for (i = 0; i != 1; ++i) {
        for (j = 8; j != 0; --j) {
            *(dst++) = hex_to_char(((src->hash[i]) >> (4 * j - 4)) & 0xF);
        }
    }

    *dst = '\0';
}

CRYPT_HASH_PREFIX void CRYPT_HASH_API crc32_d_printw(wchar_t *dst, const struct CRC32_d *src)
{
    int i, j;

    assert(dst && src && "Non-null pointer");
    
    for (i = 0; i != 1; ++i) {
        for (j = 8; j != 0; --j) {
            *(dst++) = hex_to_wchar(((src->hash[i]) >> (4 * j - 4)) & 0xF);
        }
    }

    *dst = L'\0';
}

CRYPT_HASH_PREFIX uint8_t CRYPT_HASH_API crc32_d_less(const struct CRC32_d *lhs, const struct CRC32_d *rhs)
{
    assert(lhs && rhs && "Non-null pointer");

    return lhs->hash[0] < rhs->hash[0];
}

CRYPT_HASH_PREFIX uint8_t CRYPT_HASH_API crc32_d_eq(const struct CRC32_d *lhs, const struct CRC32_d *rhs)
{
    assert(lhs && rhs && "Non-null pointer");

    return lhs->hash[0] == rhs->hash[0];
}

CRYPT_HASH_PREFIX void CRYPT_HASH_API crc32_cvt(struct CRC32_d *dst, const struct CRC32_c *src)
{
    int i;

    assert(dst && src && "Non-null pointer");

    for (i = 0; i != 1; ++i) {
        dst->hash[i] = src->hash[i];
    }
}

CRYPT_HASH_PREFIX void CRYPT_HASH_API crc32_c_init(struct CRC32_c *val)
{
    assert(val && "Non-null pointer");

    val->hash[0] = UINT32_C(0xFFFFFFFF);
    val->length = 0;
    val->append = 1;
}

CRYPT_HASH_PREFIX void CRYPT_HASH_API crc32_c_append(struct CRC32_c *val, const void *src, uint64_t len)
{
    const uint8_t *_src = src;
    const uint8_t *const _end = _src + len;
    uint32_t reg = val->hash[0];
    uint8_t cur_byte;

    assert(val && src && val->append && "Non-null pointer and append able");

    while (_end != _src) {
        cur_byte = (reg >> 24) ^ (*_src);
        reg <<= 8;
        reg ^= crc32_table[cur_byte];
        ++_src;
    }

    val->length += len;
    val->hash[0] = reg;
}

CRYPT_HASH_PREFIX void CRYPT_HASH_API crc32_c_close(struct CRC32_c *val)
{
    assert(val && val->append && "Non-null pointer and append able");

    val->hash[0] = cvt_u32_endian(~(val->hash[0]));
    val->append = 0;
}